<?php

namespace app\admin\service\common;

use think\facade\Db;
use think\facade\Log;
use InvalidArgumentException;
use Exception;
use think\Model;

class SortableService
{

    public static function sortWithModel(Model $model, array $data): void
    {
        try {
            if (!is_subclass_of($model, Model::class)) {
                throw new InvalidArgumentException('无效的模型类');
            }

            $newId = $data['newId'] ?? 0;
            $oldId = $data['oldId'] ?? 0;
            $dragPos = $data['dragPos'];
            $orderBy = array_key_exists('orderBy', $data) ? $data['orderBy'] : 'asc';

            if ($oldId <= 0 || $newId <= 0) {
                throw new InvalidArgumentException('排序参数错误');
            }

            if ($oldId === $newId) {
                return;
            }
            // 事务开始
            Db::startTrans();
            $newData = $model->find($newId);
            $oldData = $model->find($oldId);
            if (($dragPos === 'top' && $orderBy === 'asc') || ($dragPos === 'bottom' && $orderBy === 'desc')) {
                // 将大于等于新位置的排序号+1
                $model->where('sort', '>=', $newData['sort'])->setInc('sort');
                // 将拖动的行的排序号设置为新位置的排序号
                $temp = $model->where('id', '=', $oldData['id'])->find();
                $temp->sort = $newData['sort'];
                $temp->save();
            }
            if (($dragPos === 'bottom' && $orderBy === 'asc') || ($dragPos === 'top' && $orderBy === 'desc')) {
                // 将大于等于新位置的排序号+1
                $model->where('sort', '>', $newData['sort'])->inc('sort');
                // 将拖动的行的排序号设置为新位置的排序号
                $temp = $model->where('id', '=', $oldData['id']);
                $temp->sort = $newData['sort'] + 1;
                $temp->save();
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            trace([
                'data' => $data,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ],"列表排序失败");
            throw $e;
        }
    }

    /**
     * 列表排序
     * @param string $tableName
     * @param array $data
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function sort(string $tableName, array $data): void
    {
        try {
            $newId = $data['newId'] ?? 0;
            $oldId = $data['oldId'] ?? 0;
            $dragPos = $data['dragPos'];
            $orderBy = array_key_exists('orderBy', $data) ? $data['orderBy'] : 'asc';

            if ($oldId <= 0 || $newId <= 0) {
                throw new InvalidArgumentException('排序参数错误');
            }

            if ($oldId === $newId) {
                return;
            }

            // 事务开始
            Db::startTrans();
            $newData = Db::name($tableName)->find($newId);
            $oldData = Db::name($tableName)->find($oldId);
            if (($dragPos === 'top' && $orderBy === 'asc') || ($dragPos === 'bottom' && $orderBy === 'desc')) {
                // 将大于等于新位置的排序号+1
                Db::name($tableName)
                    ->where('sort', '>=', $newData['sort'])
                    ->inc('sort')
                    ->update();
                // 将拖动的行的排序号设置为新位置的排序号
                Db::name($tableName)
                    ->where('id', '=', $oldData['id'])
                    ->update(['sort' => $newData['sort']]);
            }
            if (($dragPos === 'bottom' && $orderBy === 'asc') || ($dragPos === 'top' && $orderBy === 'desc')) {
                // 将大于等于新位置的排序号+1
                Db::name($tableName)
                    ->where('sort', '>', $newData['sort'])
                    ->inc('sort')
                    ->update();
                // 将拖动的行的排序号设置为新位置的排序号
                Db::name($tableName)
                    ->where('id', '=', $oldData['id'])
                    ->update(['sort' => $newData['sort'] + 1]);
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            trace([
                'data' => $data,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ],"列表排序失败 ({$tableName})");
            throw $e;
        }
    }


    public static function treeSortWithModel(Model $model, array $data): void
    {
        if (!is_subclass_of($model, Model::class)) {
            throw new InvalidArgumentException('无效的模型类');
        }

        $newId = $data['newId'] ?? 0;
        $oldId = $data['oldId'] ?? 0;
        $dragPos = $data['dragPos'];
        $orderBy = $data['orderBy'];
        $dragToChild = $data['dragToChild'];

        if ($oldId <= 0 || $newId <= 0) {
            throw new InvalidArgumentException('排序参数错误');
        }

        if ($oldId === $newId) {
            return;
        }

        try {
            // 事务开始
            Db::startTrans();
            $newData = $model->find($newId);
            $oldData = $model->find($oldId);
            // 启用便捷拖拽成子节点，拖拽的同时按住 Ctrl 键可以自动拖放到该节点的子级
            if ($dragToChild == 'true') {
                // 查找pid为 $newData['pid'] 的所有记录中 sort的最大值
                $maxSort = $model->where('pid', $newData['pid'])->max('sort');
                // 将拖动而来的 pid 改为目的 id ，将 sort 改为此 pid = $newData[id] 中最大的
                $child = $model->where('id', '=', $oldData['id'])->find();
                $child->pid = $newData['pid'];
                $child->sort = $maxSort + 1;
                $child->save();
            } else {
                // 普通拖拽
                if (($dragPos === 'top' && $orderBy === 'asc') || ($dragPos === 'bottom' && $orderBy === 'desc')) {
                    // 将大于等于新位置的排序号+1
                    $model->where('pid', '=', $newData['pid'])
                        ->where('sort', '>=', $newData['sort'])
                        ->inc('sort');
                    // 将拖动的行的排序号设置为新位置的排序号
                    $temp = $model->where('id', '=', $oldData['id'])->find();
                    $temp->sort = $newData['sort'];
                    $temp->pid = $newData['pid'];
                    $temp->save();
                }
                if (($dragPos === 'bottom' && $orderBy === 'asc') || ($dragPos === 'top' && $orderBy === 'desc')) {
                    // 将大于等于新位置的排序号+1
                    $model->where('pid', '=', $newData['pid'])
                        ->where('sort', '>', $newData['sort'])
                        ->inc('sort');
                    // 将拖动的行的排序号设置为新位置的排序号
                    $temp = $model->where('id', '=', $oldData['id'])->find();
                    $temp->sort = $newData['sort'];
                    $temp->pid = $newData['pid'];
                    $temp->save();
                }
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            trace([
                'data' => $data,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ],"列表排序失败");
            throw $e;
        }
    }



    public static function treeSort(string $tableName, array $data): void
    {
        $newId = $data['newId'] ?? 0;
        $oldId = $data['oldId'] ?? 0;
        $dragPos = $data['dragPos'];
        $orderBy = $data['orderBy'];
        $dragToChild = $data['dragToChild'];

        if ($oldId <= 0 || $newId <= 0) {
            throw new InvalidArgumentException('排序参数错误');
        }

        if ($oldId === $newId) {
            return;
        }

        try {
            // 事务开始
            Db::startTrans();
            $newData = Db::name($tableName)->find($newId);
            $oldData = Db::name($tableName)->find($oldId);
            // 启用便捷拖拽成子节点，拖拽的同时按住 Ctrl 键可以自动拖放到该节点的子级
            if ($dragToChild == 'true') {
                // 查找pid为 $newData['pid'] 的所有记录中 sort的最大值
                $maxSort = Db::name($tableName)
                    ->where('pid', '=', $newData['id'])
                    ->max('sort');
                // 将拖动而来的 pid 改为目的 id ，将 sort 改为此 pid = $newData[id] 中最大的
                Db::name($tableName)
                    ->where('id', '=', $oldData['id'])
                    ->update(['pid' => $newData['id'], 'sort' => $maxSort + 1]);
            } else {
                // 普通拖拽
                if (($dragPos === 'top' && $orderBy === 'asc') || ($dragPos === 'bottom' && $orderBy === 'desc')) {
                    // 将大于等于新位置的排序号+1
                    Db::name($tableName)
                        ->where('pid', '=', $newData['pid'])
                        ->where('sort', '>=', $newData['sort'])
                        ->inc('sort')->update();
                    // 将拖动的行的排序号设置为新位置的排序号
                    Db::name($tableName)
                        ->where('id', '=', $oldData['id'])
                        ->update(['sort' => $newData['sort'], 'pid' => $newData['pid']]);
                }
                if (($dragPos === 'bottom' && $orderBy === 'asc') || ($dragPos === 'top' && $orderBy === 'desc')) {
                    // 将大于等于新位置的排序号+1
                    Db::name($tableName)
                        ->where('pid', '=', $newData['pid'])
                        ->where('sort', '>', $newData['sort'])
                        ->inc('sort')->update();
                    // 将拖动的行的排序号设置为新位置的排序号
                    Db::name($tableName)
                        ->where('id', '=', $oldData['id'])
                        ->update(['sort' => $newData['sort'] + 1, 'pid' => $newData['pid']]);
                }
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            trace([
                'data' => $data,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ],"列表排序失败 ({$tableName})");
            throw $e;
        }

    }



}